﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Input;
using System.Xml.Serialization;
using Antioch.Base;
using Microsoft.Xna.Framework.Content;


namespace Antioch
{
    class InputMode
    {
        public virtual void Update(EventBasedInput Input, Jemgine.Engine.Simulation Sim, Action<InputMode> SetInputMode) 
        {
            
        }

        public virtual void Draw(GraphicsDevice Device, Jemgine.Engine.Simulation Sim, Action<InputMode> SetInputMode) { }

        public static Microsoft.Xna.Framework.Input.MouseState TransformMouseState(GraphicsDevice Device, Microsoft.Xna.Framework.Input.MouseState MouseState)
        {
            MouseState = new MouseState((int)(MouseState.X * (640.0f / (float)Device.Viewport.Width)),
                (int)((Device.Viewport.Height - MouseState.Y) * (480.0f / (float)Device.Viewport.Height)),
                MouseState.ScrollWheelValue,
                MouseState.LeftButton,
                MouseState.MiddleButton,
                MouseState.RightButton,
                MouseState.XButton1,
                MouseState.XButton2);
            return MouseState;
        }

        public static Color QueryTexture(Texture2D Tex, float X, float Y)
        {
            int OX = (int)(X * Tex.Width);
            int OY = (int)(Y * Tex.Height);
            Rectangle sourceRectangle = new Rectangle(OX, OY, 1, 1);
            Color[] retrievedColor = new Color[1];

            Tex.GetData<Color>(0, sourceRectangle, retrievedColor, 0, 1);
            return retrievedColor[0];
        }

    }

    class GameInputMode : InputMode
    {
        Jemgine.Gui.Driver GuiDriver = new Jemgine.Gui.Driver();
        Jemgine.Gui.FlowLayout Layout = new Jemgine.Gui.FlowLayout();

    
        public GameInputMode(Jemgine.Engine.Simulation Sim)
        {
        }
        
        public override void Update(EventBasedInput Input, Jemgine.Engine.Simulation Sim, Action<InputMode> SetInputMode)
        {
                Sim.GetModule<Antioch.Base.GameStateModule>().Input(Input);
        }

        public override void Draw(GraphicsDevice Device, Jemgine.Engine.Simulation Sim, Action<InputMode> SetInputMode)
        {
        }
    }
    
            //var Effect = Sim.Effect;
            //var Pusher = Sim.VertexPusher;

            //Effect.ViewMatrix = Matrix.Identity;
            //Effect.ProjectionMatrix = Matrix.CreateOrthographicOffCenter(0, 640, 0, 480, -32, 0);

            //var MouseState = Mouse.GetState();
            //MouseState = TransformMouseState(Device, MouseState);

            //GuiDriver.BeginUI(MouseState);
            //Layout.BeginLayout(new Vector2(320, 240), 120, Sim.LevelData.AvailableBlocks.Count);
            //foreach (var BlockType in Sim.LevelData.AvailableBlocks)
            //{
            //    var RefCopy = BlockType;
            //    GuiDriver.MaskedButton(Layout.PositionItem(new Vector2(128, 128)),
            //        (A, B) =>
            //        {
            //            if (RefCopy.Icon == null) return true;
            //            return (QueryTexture(RefCopy.Icon, A, B).A != 0);
            //        },
            //        (A, B) =>
            //        {
            //            Effect.Texture = RefCopy.Icon == null ? Effect.SolidShadowTexture : RefCopy.Icon;
            //            if (B) Effect.Color = new Vector4(1, 0.8f, 0.8f, 1);
            //            else Effect.Color = Vector4.One;
            //            Effect.Technique = Effect.DrawFullbright;
            //            if (B)
            //            {
            //                A.X -= 8;
            //                A.Y -= 8;
            //                A.Width += 16;
            //                A.Height += 16;
            //            }
            //            Pusher.DrawAxisAlignedQuad(A.Min, A.Max);
            //        },
            //            () => { SetInputMode(new BlockPlacementInputMode(RefCopy.TemplateName, Sim)); });
            //}
            //GuiDriver.EndUI();



	partial class ScreenGame : Screen
	{
		Jemgine.Engine.Simulation World;
		
		Jemgine.Renderer.Renderer Renderer;
		Jemgine.Renderer.RenderContext RenderContext;// = new Jemgine.Renderer.RenderContext();
		SpriteFont Font;
		Texture2D YButton;

		DebugDraw _DebugDraw = new DebugDraw();
		BasicEffect BasicEffect;

		private readonly XmlSerializer serializer = new XmlSerializer(typeof(Base.SaveableState));

		Base.GameStateModule GameState = new Base.GameStateModule();
        Base.BulletModule BulletModule = null;

        InputMode InputMode = null;

		public override void Initialize()
		{
			Vector2 ViewDims = new Vector2(GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);
			float AspectRatio = ViewDims.X / ViewDims.Y;

			ViewDims.Y = 600;
			ViewDims.X = AspectRatio * 600;

			
			Renderer = new Jemgine.Renderer.Renderer(GraphicsDevice, Content);

            RenderContext = new Jemgine.Renderer.RenderContext(GraphicsDevice);
			RenderContext.Renderer = Renderer;

			RenderContext.PointTexture = Content.Load<Texture2D>("Engine.Content/_point");
            RenderContext.SolidPointTexture = Content.Load<Texture2D>("Engine.Content/_point");
			RenderContext.LineTexture = Content.Load<Texture2D>("Engine.Content/line");
			Font = Content.Load<SpriteFont>("Antioch.Content/hud");
			YButton = Content.Load<Texture2D>("Antioch.Content/controller/xboxControllerButtonY");
            
			Jemgine.Engine.Settings settings = new Jemgine.Engine.Settings();
            settings.ContentDirectory = "";// = "Antioch.Content";
            settings.Episode = Screen.CommandLineArguments.Episode;           

			World = new Jemgine.Engine.Simulation(Screen.Game.Services, GraphicsDevice, settings);

			BasicEffect = new BasicEffect(GraphicsDevice);

            GameState.SaveAction += SaveGame;
			World.AddModule(GameState);
            World.AddModule(new Base.PlayerNavigationModule());
            World.CameraModule.Init(ViewDims, 8);
            BulletModule = new BulletModule(Content);
            World.AddModule(BulletModule);

            String MapName = String.IsNullOrEmpty(Screen.CommandLineArguments.StartMap) ?
                World.LoadedEpisode.StartMap : Screen.CommandLineArguments.StartMap;
            String NodeToFire = String.IsNullOrEmpty(Screen.CommandLineArguments.FireNode) ?
                "" : Screen.CommandLineArguments.FireNode;


            if (SaveDevice.FileExists("antioch", "autosave"))
            {
                SaveDevice.Load("antioch", "autosave",
                    (A) => { GameState.PreviousSavedGame = (Base.SaveableState)serializer.Deserialize(A); });
            }
            else
                GameState.PreviousSavedGame = null;

            InitializeKeyboard();

            var SaveableState = new SaveableState { MapName = MapName, NodeToFire = NodeToFire };
            foreach (var Pair in Screen.CommandLineArguments.SaveStateOverrides)
                SaveableState.Variables.Add(Pair.Key, Pair.Value);
            GameState.InitiateGame(SaveableState, false);

            InputMode = new GameInputMode(World);
        }
        
		void SaveGame(Base.SaveableState State)
		{
            SaveDevice.Save("antioch", "autosave", (A) => serializer.Serialize(A, State));
		}

		public override void Update(GameTime gameTime)
		{
			GameState.UpdateLock.WaitOne();
            
			switch (GameState.State)
			{
				case Base.GameStateModule.States.Loading:
					break;
				case Base.GameStateModule.States.GameOver:
					break;
				case Base.GameStateModule.States.Autosave:
					break;
				case Base.GameStateModule.States.Running:

					float ElapsedSeconds = (float)gameTime.ElapsedGameTime.TotalSeconds;

					World.Update(ElapsedSeconds);

                    if (InputMode != null) InputMode.Update(Input, World, (A) => { InputMode = A; });
                   				
					break;
			}

			GameState.UpdateLock.ReleaseMutex();
		}

        public override void StickEvent(PlayerIndex index, EventBasedInput.Sticks stick,
            EventBasedInput.EventTypes type, Vector2 delta, TimeSpan duration)
        {
            if (SuppressUpdate()) return;

        }

        public override void ButtonEvent(PlayerIndex index, EventBasedInput.Buttons button, EventBasedInput.EventTypes type, TimeSpan duration)
        {
            if (index != MainController) return;

            if (SuppressUpdate()) return;

            if (GameState.State == Base.GameStateModule.States.Running
                || GameState.State == Base.GameStateModule.States.GameOver)
                if (button == EventBasedInput.Buttons.Start && type == EventBasedInput.EventTypes.Pressed)
                    PushScreen(new ScreenPauseMenu(GameState));
        }

		public override void Draw()
		{
			GraphicsDevice.Clear(Color.Black);

			switch (GameState.State)
			{
				case Base.GameStateModule.States.Loading:
					SpriteBatch.Begin();
					SpriteBatch.DrawString(Font, "Loading...", new Vector2(200, 100), Color.White);
					SpriteBatch.End();
					break;
				case Base.GameStateModule.States.GameOver:
					SpriteBatch.Begin();
					SpriteBatch.DrawString(Font, "GAMEOVER", new Vector2(200, 100), Color.White);
					SpriteBatch.End();
					break;
				case Base.GameStateModule.States.Running:

                    GameState.UpdateLock.WaitOne();

                    Renderer.BeginScene(World.CameraModule.Camera);

                    GraphicsDevice.Clear(Color.Black);
					World.Draw(GraphicsDevice);
                    if (InputMode != null) InputMode.Draw(GraphicsDevice, World, (A) => { InputMode = A; });

					BulletModule.Draw(RenderContext);

                    if (World.DebugNavigation)
                        World.GetModule<PlayerNavigationModule>().Draw(RenderContext);

					Renderer.EndScene();

                    if (World.DebugPhysics)
                    {
                        DebugDraw._batch = SpriteBatch;
                        DebugDraw._device = GraphicsDevice;
                        _DebugDraw.Flags = Box2D.XNA.DebugDrawFlags.AABB |
                        Box2D.XNA.DebugDrawFlags.CenterOfMass |
                        Box2D.XNA.DebugDrawFlags.Joint |
                        Box2D.XNA.DebugDrawFlags.Pair |
                        Box2D.XNA.DebugDrawFlags.Shape;

                        Jemgine.Engine.PhysicsModule Physics = World.GetModule<Jemgine.Engine.PhysicsModule>();
                        Physics.PhysicsSimulator.DebugDraw = _DebugDraw;
                        Physics.PhysicsSimulator.DrawDebugData();

                        BasicEffect.Projection = World.CameraModule.Camera.Projection;
                        BasicEffect.View = World.CameraModule.Camera.View;
                        BasicEffect.VertexColorEnabled = true;
                        BasicEffect.TextureEnabled = false;
                        BasicEffect.CurrentTechnique = BasicEffect.Techniques[0];
                        BasicEffect.CurrentTechnique.Passes[0].Apply();

                        _DebugDraw.FinishDrawShapes();
                    }

                    GameState.UpdateLock.ReleaseMutex();

					break;
				case Base.GameStateModule.States.Autosave:
					SpriteBatch.Begin();
					SpriteBatch.DrawString(Font, "AUTOSAVE", new Vector2(200, 100), Color.White);
					SpriteBatch.End();
					break;
			}




            DrawConsole();
		}


	}
}
